from django.shortcuts import render,redirect
from django.views import View
from django.http import HttpResponse
from django.http.response import HttpResponseBadRequest
from libs.captcha.captcha import captcha # 验证码生成库
from django_redis import get_redis_connection
from django.http import JsonResponse
from random import randint
from ronglian_sms_sdk import SmsSDK # 容联云短信验证码发送sdk
from django.conf import settings
import re
from user.models import User
from django.contrib.auth import login,authenticate,logout
from django.urls import reverse
from django.contrib.auth.mixins import LoginRequiredMixin  # 需要登录才能到达的页面函数可以继承这个类来实现
from home.models import ArticleCategory,Article
# Create your views here.

# 注册页面 页面函数
# /register
# 注册完成之后跳转到首页并保存登录状态
# 如果用户已经注册过那么也会跳转到首页
class RegisterView(View):
    
    def get(self,request):
        context = {}
        return render(request,'register.html',context=context)

    def post(self,request):
        '''
        用户填完标单点注册
        接受到的数据：mobile,password,password2,sms_code
        '''
        # 接收数据
        mobile = request.POST.get('mobile')
        password = request.POST.get('password')
        password2 = request.POST.get('password2')
        sms_code = request.POST.get('sms_code')
        # 校验数据
            # 校验是否齐全
        if not all([mobile,password,password2,sms_code]):
            return HttpResponseBadRequest('数据缺少')
            # 校验手机号是否符合
        if not re.match(r'^1[3-9]\d{9}$',mobile):
            return HttpResponseBadRequest('手机号不符合规则')
            # 校验密码是否符合规则
        if not re.match(r'^[0-9a-zA-Z]{8,20}$',password):
            return HttpResponseBadRequest('密码不符合规则，请输入8-20位的密码')
            # 校验两次密码是否一致
        if password != password2:
            return HttpResponseBadRequest('两次密码输入不一致')
            # 校验短信验证码是否跟数据库中保存的一致
        conn = get_redis_connection('default')
        redis_sms_code = conn.get('sms:%s'%mobile)
        if redis_sms_code is None:
            return HttpResponseBadRequest('短信验证码已过期')
        if sms_code != redis_sms_code.decode():
            return HttpResponseBadRequest('短信验证码不正确')
        # 保存注册信息
        # 用create_user可以给密码进行加密
        # 如果用户已存在 跳过保存数据库操作
        try:
            user = User.objects.get(username=mobile)
        except Exception:
            try:
                user = User.objects.create_user(username=mobile, password=password,phone=mobile)
            except Exception as e:
                print(e)
                return HttpResponseBadRequest('注册失败')
        # 保持登录状态
        login(request, user)
        # 返回应答
        # 暂时返回注册成功的信息
        return redirect(reverse('home:index'))

# 图片验证码 功能函数
# get 请求获取图片和图片内容
# 接受的参数 ： uuid
# 发送uuid key-value形式保存到redis
class CaptchaCode(View):

    def get(self,request):
        # 获取参数
        uuid = request.GET.get('uuid')
        # 校验数据
        if uuid is None:
            return HttpResponseBadRequest('数据不全 ')
        # 生成验证码 (返回内容和照片)
        text,image = captcha.generate_captcha()
        # redis数据库保存内容
        conn = get_redis_connection('default')
        conn.setex('img:%s'%uuid,300,text) # 过期时间为5分钟
        # 返回照片
        return HttpResponse(image,content_type='image/jpeg')

# 短信验证码 功能函数
# get 请求获取手机号图片及图片uuid
# 接受的数据：phone,image_code,uuid
class SMSCode(View):
    def get(self, request):
        # 获取数据
        phone = request.GET.get('phone')
        image_code = request.GET.get('image_code')
        uuid = request.GET.get('uuid')
        # 校验数据
        if not all([phone,image_code,uuid]):
            return JsonResponse({'res':0,'msg':'数据不完整'})
        # redis查询验证码
        conn = get_redis_connection('default')
        redis_image_code = conn.get('img:%s'%uuid)
        # 判断图片是否存在
        if redis_image_code is None:
            # 返回错误信息
            return JsonResponse({'res':1,'msg':'验证码已过期请刷新重新填入。'})
        # 如果存在就可以把他删掉
        conn.delete('img:%s'%uuid)
        # 比对图片验证码
        if redis_image_code.decode().lower() != image_code.lower():
            return JsonResponse({'res':2,'msg':'图片验证码错误。'})
        # 生成短信验证码
        sms_code = '%06d'%randint(0,999999)
        # 将短信验证码存到redis，方便后期验证
        conn.setex('sms:%s'%phone,300,sms_code)
        # 发送短信
        sdk = SmsSDK(settings.RONGLIAN_ACCOUNT_SID, settings.RONGLIAN_AUTH_TOKEN, settings.RONGLIAN_APP_ID)
        tid = '1'
        mobile = phone
        datas = (sms_code, '5')
        resp = sdk.sendMessage(tid, mobile, datas)
        # 返回应答
        return JsonResponse({'res':3,'msg':'发送成功'})

# 登录页面
class LoginView(View):
    def get(self, request):
        return render(request,'login.html')

    def post(self, request):
        # 接收数据
        mobile = request.POST.get('mobile')
        password = request.POST.get('password')
        remember = request.POST.get('remember')
        # 验证数据
            # 校验手机号是否符合
        if not re.match(r'^1[3-9]\d{9}$',mobile):
            return HttpResponseBadRequest('手机号不符合规则')
            # 校验密码是否符合规则
        if not re.match(r'^[0-9a-zA-Z]{8,20}$',password):
            return HttpResponseBadRequest('密码不符合规则，请输入8-20位的密码')
        # 验证用户
            # 我们采用django自带的认证系统
            # 默认认证username，而我们用phone，得到user模型累更改
            # 认证成功那就是user类，失败是None
        user = authenticate(request,phone=mobile,password=password)
        if user is None:
            return HttpResponseBadRequest('用户名或密码错误')
        # 状态保持
        login(request,user)
        # 是否保持状态
        if remember == 'on': # 记住用户名
            # 默认两周
            request.session.set_expiry(None)
        else: # 不记住
            # 浏览器关闭之后就没
            request.session.set_expiry(0)
        # 返回响应
        return redirect(reverse('home:index'))

# 退出登录 功能函数
class LogoutView(View):
    def get(self,request):
        # 退出登录
        logout(request)
        # 重定向到首页
        return redirect(reverse('home:index'))

# 忘记密码 页面函数
# 接收数据： 手机号 两个密码 sms_code
# 用户存在改密码，不存在注册用户
class ForgetPasswordView(View):
    def get(self,request):
        return render(request,'forget_password.html')

    def post(self,request):
        # 接收数据
        mobile = request.POST.get('mobile')
        password = request.POST.get('password')
        password2 = request.POST.get('password2')
        sms_code = request.POST.get('sms_code')
        # 校验数据
            # 校验是否齐全
        if not all([mobile,password,password2,sms_code]):
            return HttpResponseBadRequest('数据缺少')
            # 校验手机号是否符合
        if not re.match(r'^1[3-9]\d{9}$',mobile):
            return HttpResponseBadRequest('手机号不符合规则')
            # 校验密码是否符合规则
        if not re.match(r'^[0-9a-zA-Z]{8,20}$',password):
            return HttpResponseBadRequest('密码不符合规则，请输入8-20位的密码')
            # 校验两次密码是否一致
        if password != password2:
            return HttpResponseBadRequest('两次密码输入不一致')
            # 校验短信验证码是否跟数据库中保存的一致
        conn = get_redis_connection('default')
        redis_sms_code = conn.get('sms:%s'%mobile)
        if redis_sms_code is None:
            return HttpResponseBadRequest('短信验证码已过期')
        if sms_code != redis_sms_code.decode():
            return HttpResponseBadRequest('短信验证码不正确')
        # 按照账户信息查询用户
        # 如果存在进行更改密码，如果不存在进行新用户注册
        try:
            user = User.objects.get(phone=mobile)
            user.set_password(password)
            user.save()
        except User.DoesNotExist:
            try:
                user = User.objects.create_user(username=mobile, password=password,phone=mobile)
            except Exception as e:
                print(e)
                return HttpResponseBadRequest('注册失败')
        # 记住用户状态
        login(request, user)
        # 返回应答
        return redirect(reverse('home:index'))

# 个人信息 页面函数
# get请求显示页面 post请求修改信息
# 接受的数据:用户名，头像，简介
class UserCenterView(LoginRequiredMixin,View):
    def get(self,request):
        return render(request, 'center.html')

    def post(self,request):
        user = request.user
        # 接收数据 如果没有就默认拿上数据库里的
        username = request.POST.get('username',user.username)
        user_desc = request.POST.get('desc',user.desc)
        avatar = request.FILES.get('avatar')
        # 数据保存数据库
        try:
            user.username = username
            user.desc = user_desc
            if avatar:
                user.avatar = avatar
            user.save()
        except Exception as e:
            print(e)
            return HttpResponseBadRequest('信息修改失败，请稍候重试。')
        # 返回响应
        return redirect(reverse('user:center'))

# 写文整 页面函数
class WriteView(LoginRequiredMixin,View):
    def get(self,request):
        categories = ArticleCategory.objects.all()
        context = {
            'categories':categories
        }
        return render(request,'write_blog.html',context=context)

    def post(self,request):
        # 接收数据
        avatar = request.FILES.get('avatar')
        title = request.POST.get('title')
        category_id = request.POST.get('category')
        tags = request.POST.get('tags')
        sumary = request.POST.get('sumary')
        content = request.POST.get('content')
        user = request.user
        # 校验数据
        if not all([avatar, title, category_id, sumary, content]):
            return HttpResponseBadRequest('参数不全')
        # 判断分类是否存在
        try:
            category = ArticleCategory.objects.get(id=category_id)
        except ArticleCategory.DoesNotExist:
            return HttpResponseBadRequest('没有次分类')
        # 写入数据库
        try:
            Article.objects.create(
                author = user,
                avatar = avatar,
                title = title,
                category = category,
                tags = tags,
                summary = sumary,
                content = content,
            )
        except Exception as e:
            print(e)
            return HttpResponseBadRequest('文章发布失败，请稍候重试。')
        # 返回应答
        return redirect(reverse('home:index'))
        

# if __name__ == '__main__':
#     res = re.match(r'^[0-9a-zA-Z]{8,20}$','12345678')
#     print(res)